#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/atomic.h>
#include <linux/spinlock_types.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>

static struct task_struct * slam1, * slam2;
static atomic_t slam_atomic;

static int slam_spinlock_value = 0;
DEFINE_SPINLOCK(slam_spinlock);

static int slam_semaphore_value = 1;
static struct semaphore slam_semaphore;

static int slam_mutex_value = 2;
DEFINE_MUTEX(slam_mutex);

extern unsigned long msleep_interruptible(unsigned int msecs);

static int slam1_func(void *data)
{
	do{
		printk("slam_atomic.counter=%d\n", atomic_read(&slam_atomic));

		spin_lock(&slam_spinlock);
		printk("slam1-1 slam_spinlock_value=%d\n", slam_spinlock_value);
		slam_spinlock_value=1;
		printk("slam1-2 slam_spinlock_value=%d\n", slam_spinlock_value);
		spin_unlock(&slam_spinlock);

		down(&slam_semaphore);
		printk("slam1-1 slam_semaphore_value=%d\n", slam_semaphore_value);
		slam_semaphore_value=1;
		printk("slam1-2 slam_semaphore_value=%d\n", slam_semaphore_value);
		up(&slam_semaphore);

		mutex_lock(&slam_mutex);
		printk("slam1-1 slam_mutex_value=%d\n",slam_mutex_value);
		slam_mutex_value=1;
		printk("slam1-2 slam_mutex_value=%d\n",slam_mutex_value);
		mutex_unlock(&slam_mutex);

		msleep_interruptible(500);
	}while(!kthread_should_stop());

	return 0;
}

static int slam2_func(void *data)
{
	do{
		atomic_inc(&slam_atomic);

		spin_lock(&slam_spinlock);
		printk("slam2-1 slam_spinlock_value=%d\n", slam_spinlock_value);
		slam_spinlock_value=2;
		printk("slam2-2 slam_spinlock_value=%d\n", slam_spinlock_value);
		spin_unlock(&slam_spinlock);

		down(&slam_semaphore);
		printk("slam2-1 slam_semaphore_value=%d\n", slam_semaphore_value);
		slam_semaphore_value=2;
		printk("slam2-2 slam_semaphore_value=%d\n", slam_semaphore_value);
		up(&slam_semaphore);

		mutex_lock(&slam_mutex);
		printk("slam2-1 slam_mutex_value=%d\n",slam_mutex_value);
		slam_mutex_value=2;
                printk("slam2-2 slam_mutex_value=%d\n",slam_mutex_value);
		mutex_unlock(&slam_mutex);

		msleep_interruptible(500);
	}while(!kthread_should_stop());

	return 0;
}

static __init int kthread_lock_init(void)
{
	atomic_set(&slam_atomic, 2);
	sema_init(&slam_semaphore, 2);

	slam1 = kthread_run(slam1_func, NULL, "slam1");
	if(IS_ERR(slam1))
	{
		printk("kthread_run slam1 failed!\n");
		return 1;
	}

	slam2 = kthread_run(slam2_func, NULL, "slam2");
	if(IS_ERR(slam2))
	{
		printk("kthread_run slam2 failed!\n");
		return 1;
	}

	return 0;
}

static __exit void kthread_lock_exit(void)
{
	if(!IS_ERR(slam1))
	      kthread_stop(slam1);

	if(!IS_ERR(slam2))
	      kthread_stop(slam2);
}

module_init(kthread_lock_init);
module_exit(kthread_lock_exit);
